#include "HttpRequest.h"

#include <QEventLoop>
#include <QJsonObject>
#include <QJsonParseError>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QByteArray>
#include <QNetworkReply>
#include <QJsonArray>
#include <QFile>
#include <QFileInfo>
#include <QHttpPart>
#include <QUrlQuery>
#include "MyJson.h"

QString HttpRequest::m_scheme = "http";
QString HttpRequest::m_serverAddr = "0.0.0.0";
QString HttpRequest::m_port = "5000";
QString HttpRequest::m_requestHeader;
QHash<QString, QString> HttpRequest::m_receive_data;
QVariantMap HttpRequest::m_map_post;
QVariantMap HttpRequest::m_map_get;


QHash<QString, QString> HttpRequest::getReceive_data()
{
    return m_receive_data;
}

void HttpRequest::setReceive_data(const QHash<QString, QString> &receive_data)
{
    m_receive_data = receive_data;
}

QVariantMap HttpRequest::getMap_post()
{
    return m_map_post;
}

void HttpRequest::setMap_post(const QVariantMap &map_post)
{
    m_map_post = map_post;
}

QVariantMap HttpRequest::getMap_get()
{
    return m_map_get;
}

void HttpRequest::setMap_get(const QVariantMap &map_get)
{
    m_map_get = map_get;
}

HttpRequest::HttpRequest(QObject *parent, QString scheme = "http", QString serverAddr = "127.0.0.1", QString port = "5000")
    : QObject(parent)
{

    m_scheme = scheme;  // 协议
    m_serverAddr = serverAddr;  // 地址
    m_port = port;  // 端口号

    m_requestHeader = scheme + QString("://") + serverAddr + QString(":") + port;
}

HttpRequest::HttpRequest(QObject *parent, const QString &url)
    : QObject(parent), m_url(url)
{
    // 初始化QNetworkAccessManager对象
    m_networkManager = new QNetworkAccessManager(this);
}

HttpRequest::HttpRequest(QObject *parent,const HttpRequest &hr)
    : QObject(parent)
{
    this->m_url = hr.m_url;

    // 执行深拷贝
    if(hr.m_networkManager != nullptr)
    {
        this->m_networkManager = new QNetworkAccessManager(hr.m_networkManager);
    } else {
        this->m_networkManager = nullptr;
    }
}

HttpRequest &HttpRequest::operator=(const HttpRequest &hr)
{
    // 检查自我赋值
    if(this == &hr)
    {
        return *this;
    }

    // 执行深拷贝
    if(hr.m_networkManager != nullptr)
    {
        this->m_networkManager = new QNetworkAccessManager(hr.m_networkManager);
    } else {
        this->m_networkManager = nullptr;
    }
    return *this;
}

HttpRequest::~HttpRequest()
{
    // 释放分配的内存
    delete m_networkManager;
}


int HttpRequest::NormalGetRequest(QString path, const QMap<QString, QString> &keyValuePairs)
{
    //生成对应的网络请求
    QNetworkRequest request;

    QString fullRequest = m_requestHeader + path;


    // 不为空就添加
    if(!keyValuePairs.isEmpty())
    {
        fullRequest += "?";

        QStringList parameters;
        for(const QString &paramer : keyValuePairs.keys())
        {
            parameters += paramer + "=" + keyValuePairs.value(paramer);
            qDebug() << "paramer:" << paramer << "\t pararmeters:" << parameters;
        }
        fullRequest += parameters.join("&");
        qDebug() << "fullRequest:" << fullRequest;
    }
    // 路径
    m_url = fullRequest;

    request.setUrl(QUrl(m_url));

    //发送Get请求
    QNetworkAccessManager manager;
    QNetworkReply *reply = manager.get(request);
    QEventLoop eventLoop;
    connect(reply,&QNetworkReply::finished,&eventLoop, &QEventLoop::quit);
    eventLoop.exec(QEventLoop::ExcludeUserInputEvents);

    //对请求的返回异常进行处理
    if(reply->error() != QNetworkReply::NoError)
    {
        qDebug() << "GET Reply Error:" << reply->errorString();
        return reply->error();
    }


    //解析返回的Json结果
    QByteArray replyData = reply->readAll();
    QJsonParseError json_error;
    QJsonDocument jsonDoc(QJsonDocument::fromJson(replyData, &json_error));
    if(json_error.error != QJsonParseError::NoError)
    {
        qDebug() << "replyData : " << replyData;
        qDebug() << "JSON : " << jsonDoc.object();
        qDebug() << "GET Json Error:" << json_error.errorString();
        return -1;
    }
    m_map_get = jsonDoc.toVariant().toMap();
    QJsonObject rootObj = jsonDoc.object();
    QString codeStr = rootObj.value("code").toString();
    if (codeStr.compare("200") == 0)
    {
        //返回代码为200的时候证明请求成功对包含的结构数据进行处理
        if(rootObj.contains("data"))
        {
            if(getJsonDatas(rootObj, ""))
            {
                // 成功
                qDebug() << "POST成功";



//                // Map字典
//                QVariantMap map = jsonDoc.toVariant().toMap();
//                qDebug() << "Map字典: ";

//                qDebug() << map.values();




            } else {
                // 失败
                qDebug() << "POST失败";
            }
        }
        return 0;
    }
    else
    {
        //请求失败对对应的处理
        return codeStr.toInt();
    }
}


int HttpRequest::NormalPostRequest(QString path, const QMap<QString, QString> &keyValuePairs)
{

    //生成对应的网络请求
    QNetworkRequest request;

    QString fullRequest = m_requestHeader + path;

    // 路径
    m_url = fullRequest;

    request.setUrl(QUrl(m_url));
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");

    // 构建POST数据
    QUrlQuery postData;


    // 不为空
    if(!keyValuePairs.isEmpty())
    {
        // 添加请求体
        for(const QString &value: keyValuePairs.keys())
        {
            postData.addQueryItem(value, keyValuePairs.value(value));
        }
        qDebug() << "postData:" << postData.toString();
    }


    //发送请求
    QNetworkAccessManager manager;
    QNetworkReply *reply = manager.post(request, postData.toString(QUrl::FullyEncoded).toUtf8());
    QEventLoop eventLoop;
    QObject::connect(reply, SIGNAL(finished()),&eventLoop, SLOT(quit()));
    eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
    if(reply->error() != QNetworkReply::NoError)
    {
        qDebug() << "POST Reply Error:" << reply->errorString();
        return reply->error();
    }

    //解析返回的Json结果
    QByteArray replyData = reply->readAll();
    QJsonParseError json_error;
    QJsonDocument jsonDoc(QJsonDocument::fromJson(replyData, &json_error));
    if(json_error.error != QJsonParseError::NoError)
    {
        qDebug() << "POST Json Error:" << json_error.errorString();
        return -1;
    }

    // Json对象
    QJsonObject rootObj = jsonDoc.object();

    m_map_post = jsonDoc.toVariant().toMap();


    if(getJsonDatas(rootObj, ""))
    {
        // 成功
        qDebug() << "POST成功";
    } else {
        // 失败
        qDebug() << "POST失败";
    }

    return rootObj.value("code").toInt();
}

//int HttpRequest::sendRequest(const QNetworkRequest &request)
//{


//}

int HttpRequest::PostRequestWithFile(QString paramer1, QString paramer2, QString filePath)
{
    //生成对应的网址请求
    QFileInfo fileInfo(filePath);
    QString fileName =fileInfo.fileName();

    QFile* inputFile = new QFile(filePath);
    inputFile->open(QIODevice::ReadOnly);

    //multipart请求
    QHttpMultiPart* multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
    //文件块
    QHttpPart filePart;
    filePart.setHeader(QNetworkRequest::ContentDispositionHeader,
                       QVariant(QString("form-data; name=\"uploadfile\";filename=\"%1\"").arg(fileName)));
    filePart.setBodyDevice(inputFile);
    inputFile->setParent(multiPart);
    multiPart->append(filePart);

    QHttpPart paramer1Part;
    paramer1Part.setHeader(QNetworkRequest::ContentDispositionHeader,QVariant("form-data; name=\"paramer1\""));
    paramer1Part.setBody(paramer1.toUtf8());
    multiPart->append(paramer1Part);

    QHttpPart paramer2Part;
    paramer2Part.setHeader(QNetworkRequest::ContentDispositionHeader,QVariant("form-data; name=\"paramer2\""));
    paramer2Part.setBody(paramer2.toUtf8());
    multiPart->append(paramer2Part);


    //生成对应的网址请求
    QNetworkRequest request;
    QString scheme = "http";
    QString serverAddr = "192.168.0.1";
    QString port = "80";
    QString requestHeader = scheme + QString("://") + serverAddr + QString(":") + port;
    QString fullRequest = requestHeader + "/api/v1/user/postrequestwithfile";
    request.setUrl(QUrl(fullRequest));

    //发送请求
    QNetworkAccessManager manager;
    QNetworkReply *reply = manager.post(request,multiPart);
    multiPart->setParent(reply);

    QEventLoop eventLoop;
    QObject::connect(&manager, SIGNAL(finished(QNetworkReply*)),&eventLoop, SLOT(quit()));
    eventLoop.exec(QEventLoop::ExcludeUserInputEvents);

    if(reply->error() != QNetworkReply::NoError)
    {
        return reply->error();
    }

    //解析返回的Json结果
    QByteArray replyData = reply->readAll();
    QJsonParseError json_error;
    QJsonDocument jsonDoc(QJsonDocument::fromJson(replyData, &json_error));
    if(json_error.error != QJsonParseError::NoError)
    {
        return -1;
    }
    QJsonObject rootObj = jsonDoc.object();
    QString codeStr = rootObj.value("code").toString();
    if (codeStr.compare("200") == 0)
    {
        //返回代码为200的时候证明请求成功对包含的结构数据进行处理
        if(rootObj.contains("result"))
        {

        }
        return 0;
    }
    else
    {
        //请求失败对对应的处理
        return codeStr.toInt();
    }

}

int HttpRequest::DownloadFileFromWeb(QString fileUrl, QString &fileSavePath)
{
    QNetworkRequest request;
    QUrl url(fileUrl);
    QFileInfo fileInfo(url.path());
    QString fileName = fileInfo.fileName();
    QNetworkAccessManager *accessManager=new QNetworkAccessManager();
    request.setUrl(url);
    QNetworkReply *reply  = accessManager->get(request);
    QEventLoop loop;
    QObject::connect(accessManager, SIGNAL(finished(QNetworkReply*)), &loop, SLOT(quit()));
    //如果需要下载进度需要关联对应的信号
    //connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(LoadProgress(qint64, qint64)));
    loop.exec(QEventLoop::ExcludeUserInputEvents);

    //获取下载返回值
    QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
    if (statusCode.toInt() != 200)
    {
        return -1;
    }

    //保存下载的文件
    QFile file(fileSavePath);
    if(!file.open(QIODevice::WriteOnly))
    {
        return -2;
    }
    file.write(reply->readAll());
    file.close();
    return 0;
}

void HttpRequest::do_RequestFinished()
{
    // 处理响应
    QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
    if (reply) {
        if (reply->error() == QNetworkReply::NoError) {
            // 读取并处理响应数据
            QByteArray data = reply->readAll();
            // ...
        } else {
            // 处理错误
            qDebug() << "Error: " << reply->errorString();
        }

        // 清理资源
        reply->deleteLater();
    }
}

void HttpRequest::uploadFile(const QString& fileName, const QString& url) {
    // 创建文件对象
    QFile file(fileName);
    if(!file.open(QIODevice::ReadOnly)) {
        // 打开文件失败
        qDebug() << "Failed to open file:" << fileName;
        return;
    }

    // 创建网络请求
    QNetworkAccessManager manager;
    QNetworkRequest request(url);

    // 设置请求头
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/octet-stream");
    request.setHeader(QNetworkRequest::ContentLengthHeader, file.size());

    // 发送 POST 请求
    QNetworkReply* reply = manager.post(request, &file);

    // 处理响应
    connect(reply, &QNetworkReply::finished, [&](){
        if(reply->error() == QNetworkReply::NoError) {
            qDebug() << "Upload file" << fileName << "successfully!";
        } else {
            qDebug() << "Failed to upload file:" << fileName << ", error:" << reply->errorString();
        }
        file.close();
        reply->deleteLater();
    });
}


QString HttpRequest::scheme()
{
    return m_scheme;
}

void HttpRequest::setScheme(const QString &scheme)
{
    m_scheme = scheme;
}

QString HttpRequest::serverAddr()
{
    return m_serverAddr;
}

void HttpRequest::setServerAddr(const QString &serverAddr)
{
    m_serverAddr = serverAddr;
}

QString HttpRequest::port()
{
    return m_port;
}

void HttpRequest::setPort(const QString &port)
{
    m_port = port;
}

QString HttpRequest::requestHeader()
{
    return m_requestHeader;
}

void HttpRequest::setRequestHeader(const QString &requestHeader)
{
    m_requestHeader = requestHeader;
}

void HttpRequest::setNetworkManager(QNetworkAccessManager* manager)
{
    m_networkManager = manager;
}

QNetworkAccessManager* HttpRequest::getNetworkManager() const
{
    return m_networkManager;
}
